/*
 * CGlobalLog.h
 *
 *  Created on: Oct 24, 2011
 *      Author: fferri
 */
#ifndef GLOG_CGLOBALLOG_H_
#define GLOG_CGLOBALLOG_H_

#include "singleton.h"
#include "LogLevels.h"
#include "IListener.h"
#include "StoredMessage.h"
#include <memory.h>
#include <queue>
#include <vector>
#include <map>
#include <list>
#include <cstdarg>
#include <boost/shared_ptr.hpp>

namespace glog {

	/*
	 *
	 */
	class CGlobalLog: public Singleton<glog::CGlobalLog>{
	private:
		// needed for singleton implementation
		friend class Singleton<glog::CGlobalLog>;
		friend class std::auto_ptr<glog::CGlobalLog>;

		/// The global minimun level. Below this level no message is recorded.
		LogLevel m_minimumLevel;

		// privated constructor and destructor
		CGlobalLog();
		virtual ~CGlobalLog();

		// typedefs
		/// Asi guardamos las colas de referencias a mensajes.
		typedef std::queue<CStoredMessage*> t_msgQueue;
		/// Asi guardamos la lista de listeners (las clases suscritas a las colas de mensajes)
		typedef std::list<boost::shared_ptr<IListener> > t_ListenerList;
		/// Asi es como guardo las colas de mensajes ordenadas por appender
		typedef std::map<std::string, t_msgQueue> t_appenderQueueMap;
		/// Asi es como relaciono clasifico, para cada appender, los listeners asociados.
		typedef std::map<std::string, t_ListenerList> t_appenderToListenerListMap;

		/// Guarda las colas de mensajes agrupadas por appender
		t_appenderQueueMap m_msgQueue;
		/// Guarda los grupos de listeners agrupados por el appender al que estan suscritos.
		t_appenderToListenerListMap m_suscriptionMap;

		void addMessage_(const std::string& appender, LogLevel level,const char* msg, va_list args );
	public:
		/**
		 * Sets the minimum log level in which log records a message. Below this error level message will be ignored.
		 */
		void setMiniumLevel(const LogLevel lvl);
		/**
		 * Sets the minimum log level.
		 */
		LogLevel getMinimunLevel() const;
		/**
		 * Adds a new appender. An appender is a name for a group o messages.
		 */
		void addAppender(const std::string& app);
		/**
		 * Gets a list of the current appenders
		 */
		std::list<std::string> getAppenderList() const;

		/**
		 * Adds a listener that listen to an appender
		 */
		void addListener(boost::shared_ptr<IListener> l, const std::string& appender);
#ifndef GLOG_SILENCE
		/**
		 * Process the messages hold by the queues and send to its corresponding appenders
		 */
		void processMessages();
		/**
		 * Writes a message with a serverity level of DEBUG into que queue.
		 * \param appender The appender where meesage is grouped.
		 * \param message The message stored.
		 */
		void DEBUG_MSG(const std::string& appender,const char* msg, ...);
		/**
		 * Writes a message with a serverity level of INFO into que queue.
		 * \param appender The appender where meesage is grouped.
		 * \param message The message stored.
		 */
		void INFO_MSG(const std::string& appender,const char* msg, ...);
		/**
		 * Writes a message with a serverity level of WARNING into que queue.
		 * \param appender The appender where meesage is grouped.
		 * \param message The message stored.
		 */
		void WARNING_MSG(const std::string& appender, const char* msg, ...);
		/**
		 * Writes a message with a serverity level of ERROR into que queue.
		 * \param appender The appender where meesage is grouped.
		 * \param message The message stored.
		 */
		void ERROR_MSG(const std::string& appender, const char* msg, ...);
		/**
		 * Writes a message with a serverity level of FATAL into que queue.
		 * \param appender The appender where meesage is grouped.
		 * \param message The message stored.
		 */
		void FATAL_MSG(const std::string& appender, const char* msg, ...);
		/**
		 * Adds a message to be processed.
		 * \param appender The appender where meesage is grouped.
		 * \param lvl The level of severity of the message
		 * \param message The message stored.
		 */
		void addMessage(const std::string& appender, LogLevel lvl, const std::string& message);
#else //GLOG_SILENCE
		// to fully remove this function use compiler optimizations in order to be replaced by nothing at compile time
		void doNothing(){}
		#define processMessages(...) 	doNothing()
		#define DEBUG_MSG(...)			doNothing()
		#define INFO_MSG(...) 			doNothing()
		#define WARNING_MSG(...) 		doNothing()
		#define ERROR_MSG(...) 			doNothing()
		#define FATAL_MSG(...)			doNothing()
		#define addMessage(...)			doNothing()
#endif //GLOG_SILENCE

	};

} /* namespace glog */
#endif /* GLOG_CGLOBALLOG_H_ */
